package dao

import (
	"fmt"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/core/model/pipeline"
	"gitee.com/gitee-go/server/comm/notice"
	"gitee.com/gitee-go/server/service"
	"runtime/debug"
	"strconv"
	"time"

	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/runtime"
	"gitee.com/gitee-go/server/comm"
)

/*
UpdateJob : update job when building
*/
func UpdateJob(job *runtime.Job) (rterr error) {
	tms := time.Now()
	defer func() {
		core.Log.Debugf("UpdateJob end:%.4fs", time.Since(tms).Seconds())
		if err := recover(); err != nil {
			core.LogPnc.Errorf("UpdateBuild:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()
	core.Log.Debugf("UpdateJob start!!!!")
	db := comm.DBMain.NewSession()
	tJob := &pipeline.TJob{
		Status:   job.Status,
		ExitCode: int64(job.ExitCode),
		Error:    job.Error,
		Finished: job.Finished,
		Updated:  time.Now(),
		Started:  job.Started,
	}

	_, err := db.
		Where("id = ?", job.Id).
		Cols("status,exit_code,error,finished,updated,started").
		Update(tJob)

	if err != nil {
		core.Log.Errorf("task update job err : %v", err)
		return err
	}
	return nil
}

/*
UpdateStage : update stage when building
*/
// 更新stage状态,包括它的job
func UpdateStage(stage *runtime.Stage) (rterr error) {
	tms := time.Now()
	defer func() {
		core.Log.Debugf("UpdateStage end:%.4fs", time.Since(tms).Seconds())
		if err := recover(); err != nil {
			core.LogPnc.Errorf("UpdateBuild:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()
	core.Log.Debugf("UpdateStage start!!!!")
	db := comm.DBMain.NewSession()

	ts := &pipeline.TStage{
		Status:    stage.Status,
		ExitCode:  int64(stage.ExitCode),
		Error:     stage.Error,
		Finished:  stage.Finished,
		Updated:   time.Now(),
		OnSuccess: strconv.FormatBool(stage.OnSuccess),
		OnFailure: strconv.FormatBool(stage.OnFailure),
		Started:   stage.Started,
	}

	_, err := db.
		Where("id = ?", stage.Id).
		Cols("status,exit_code,error,timestamp,finished,updated,started,on_success,on_failure").
		Update(ts)

	if err != nil {
		core.Log.Errorf("task update job err : %v", err)
		return err
	}
	return nil
}

/*
UpdateBuild : when build finished update build msg
*/
func UpdateBuild(bld *runtime.Build) (rterr error) {
	tms := time.Now()
	defer func() {
		core.Log.Debugf("UpdateBuild end:%.4fs", time.Since(tms).Seconds())
		if err := recover(); err != nil {
			core.LogPnc.Errorf("UpdateBuild:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()
	defer noticeBuildStatus(bld) // 构建完成发送站内信
	core.Log.Debugf("UpdateBuild start!!!!")

	db := comm.DBMain.NewSession()
	build := &pipeline.TBuild{
		Id:        bld.Id,
		Status:    bld.Status,
		Error:     bld.Error,
		Event:     bld.Event,
		TimeStamp: bld.Timestamp,
		Message:   bld.Message,
		Started:   bld.Started,
		Finished:  bld.Finished,
		Updated:   time.Now(),
	}

	_, err := db.
		Where("id = ?", bld.Id).
		Cols("status,error,event,timestamp,message,started,finished,updated").
		Update(build)

	if err != nil {
		return err
	}

	cfg := bld.Cfg
	pipe := cfg.Pipe
	stages := pipe.Stages
	// 循环更新stage
	for _, stage := range stages {
		if common.BuildStatusEnded(build.Status) && !common.BuildStatusEnded(stage.Status) {
			stage.Status = build.Status
		}
		ts := &pipeline.TStage{
			Status:    stage.Status,
			ExitCode:  int64(stage.ExitCode),
			Error:     stage.Error,
			Finished:  stage.Finished,
			Updated:   time.Now(),
			OnSuccess: strconv.FormatBool(stage.OnSuccess),
			OnFailure: strconv.FormatBool(stage.OnFailure),
			Started:   stage.Started,
		}

		_, err = db.
			Where(" id= ?  ", stage.Id).
			Cols("status,exit_code,error,timestamp,finished,updated,started,on_success,on_failure").
			Update(ts)

		if err != nil {
			return err
		}

		jobs := stage.Jobs
		// 循环更新job
		for _, job := range jobs {
			if common.BuildStatusEnded(build.Status) && !common.BuildStatusEnded(job.Status) {
				job.Status = build.Status
			}
			tJob := &pipeline.TJob{
				Status:   job.Status,
				ExitCode: int64(job.ExitCode),
				Error:    job.Error,
				Finished: job.Finished,
				Updated:  time.Now(),
				Started:  job.Started,
			}

			_, err = db.
				Where("id = ?", job.Id).
				Cols("status,exit_code,error,finished,updated,started").
				Update(tJob)

			if err != nil {
				return err
			}
		}

	}
	return nil
}

// 发送构建情况站内信
func noticeBuildStatus(build *runtime.Build) {
	if !common.BuildStatusEnded(build.Status) {
		return
	}
	tb := &pipeline.TBuild{}
	get, err := comm.DBMain.GetDB().Where("id = ?", build.Id).Get(tb)
	if err != nil {
		core.Log.Errorf("UpdateBuild defer db err: %v", err)
	}
	if !get {
		return
	}
	version := &pipeline.TPipelineVersion{}
	get, err = comm.DBMain.GetDB().Where("id = ?", tb.PipelineVersionId).Get(version)
	if err != nil {
		core.Log.Errorf("UpdateBuild defer db err: %v", err)
	}
	if !get {
		return
	}
	tr := &pipeline.TRepo{}
	get, err = comm.DBMain.GetDB().Where("id = ?", version.RepoId).Get(tr)
	if err != nil {
		core.Log.Errorf("UpdateBuild defer db err: %v", err)
	}
	if !get {
		return
	}
	d := &notice.NoticeDetail{
		Version:           strconv.FormatInt(version.Number, 10),
		Branch:            fmt.Sprintf("%v(%v)", version.Branch, version.CommitSha),
		FullName:          tr.FullName,
		Result:            notice.BuildContent(build.Status, version.PipelineName),
		MStatus:           build.Status,
		PipelineVersionId: version.Id,
		RepoId:            tr.Id,
		Openid:            tr.Openid,
		VersionStatus:     common.PIPELINE_VERSION_STATUS_OK,
	}
	marshal, _ := d.Marshal()
	// 插入站内信到数据库
	err = service.InsertNoticesByRepo(tr, &notice.Notice{
		Content: notice.BuildContent(build.Status, version.PipelineName),
		Types:   common.MSG_TYPES_SYSYTEM,
		Infos:   marshal,
		Url:     "",
	})
	if err != nil {
		core.Log.Errorf("UpdateBuild InsertNoticesByRepo err: %v", err)
	}
}
